#include "stdafx.h"
#include "SpriteFontLoader.h"
#include "../Helpers/BinaryReader.h"
#include "../Content/ContentManager.h"
#include "../Graphics/TextRenderer.h"


SpriteFontLoader::SpriteFontLoader()
{

}


SpriteFontLoader::~SpriteFontLoader()
{
}

SpriteFont* SpriteFontLoader::LoadContent(const wstring& assetFile)
{
	auto binReader = new BinaryReader();
	binReader->Open(assetFile);

	if (!binReader->Exists())
	{
		Logger::LogFormat(LogLevel::Error, L"SpriteFontLoader::LoadContent > Failed to read the assetFile!\nPath: \'%s\'", assetFile.c_str());
		return nullptr;
	}

	//See BMFont Documentation for Binary Layout
	
	//Parse the Identification bytes (B,M,F)
	char fileId1 = binReader->Read<char>();
	char fileId2 = binReader->Read<char>();
	char fileId3 = binReader->Read<char>();

	//If Identification bytes doesn't match B|M|F,
	//Log Error (SpriteFontLoader::LoadContent > Not a valid .fnt font) &
	//return nullptr
	//...PHYSX FLEX
	if (fileId1 != 'B' || fileId2 != 'M' || fileId3 != 'F')
	{
		Logger::LogError(L"SpriteFontLoader::LoadContent > Not a valid .fnt font");
		return nullptr;
	}

	//Parse the version (version 3 required)
	//If version is < 3,
	//Log Error (SpriteFontLoader::LoadContent > Only .fnt version 3 is supported)
	//return nullptr
	//...
	int version = binReader->Read<char>();
	if (version != 3)
	{
		Logger::LogError(L"SpriteFontLoader::LoadContent > Only .fnt version 3 is supported");
		return nullptr;
	}

	//Valid .fnt file
	auto pSpriteFont = new SpriteFont();
	//SpriteFontLoader is a friend class of SpriteFont
	//That means you have access to its privates (pSpriteFont->m_FontName = ... is valid)

	//**********
	// BLOCK 0 *
	//**********
	//Retrieve the blockId and blockSize
	int blockId = binReader->Read<char>();
	int blockSize = binReader->Read<int>();
	//Retrieve the FontSize (will be -25, BMF bug) [SpriteFont::m_FontSize]
	pSpriteFont->m_FontSize = binReader->Read<short>();
	//Move the binreader to the start of the FontName [BinaryReader::MoveBufferPosition(...) or you can set its position using BinaryReader::SetBufferPosition(...))
	//binReader->SetBufferPosition(blockSize);
	binReader->MoveBufferPosition(12);
	//Retrieve the FontName [SpriteFont::m_FontName]
	pSpriteFont->m_FontName = binReader->ReadNullString();

	//**********
	// BLOCK 1 *
	//**********
	//Retrieve the blockId and blockSize
	blockId = binReader->Read<char>();
	blockSize = binReader->Read<int>();
	//Retrieve Texture Width & Height [SpriteFont::m_TextureWidth/m_TextureHeight]
	binReader->MoveBufferPosition(4);
	pSpriteFont->m_TextureWidth = binReader->Read<short>();

	pSpriteFont->m_TextureHeight = binReader->Read<short>();

	//Retrieve PageCount
	int pageCount = binReader->Read<short>();

	//> if pagecount > 1
	//> Log Error (SpriteFontLoader::LoadContent > SpriteFont (.fnt): Only one texture per font allowed)
	if (pageCount > 1)
	{
		Logger::LogError(L"SpriteFontLoader::LoadContent > SpriteFont (.fnt): Only one texture per font allowed");
		return nullptr;
	}
	//Advance to Block2 (Move Reader)
	binReader->MoveBufferPosition(5);

	//**********
	// BLOCK 2 *
	//**********
	//Retrieve the blockId and blockSize
	blockId = binReader->Read<char>();
	blockSize = binReader->Read<int>();
	//Retrieve the PageName (store Local)
	wstring pageName = binReader->ReadNullString();
	//	> If PageName is empty
	if (pageName.empty())
	{
		Logger::LogError(L"SpriteFontLoader::LoadContent > SpriteFont (.fnt): Invalid Font Sprite [Empty]");
		return nullptr;
	}

	//> Log Error (SpriteFontLoader::LoadContent > SpriteFont (.fnt): Invalid Font Sprite [Empty])
	//>Retrieve texture filepath from the assetFile path
	//> (ex. c:/Example/somefont.fnt => c:/Example/) [Have a look at: wstring::rfind()]
	wstring filePath = assetFile;
	wstring searchName = pageName.substr(0, pageName.size() - 6);
	filePath = filePath.substr(0, filePath.rfind(searchName));
	//>Use path and PageName to load the texture using the ContentManager [SpriteFont::m_pTexture]
	//> (ex. c:/Example/ + 'PageName' => c:/Example/somefont_0.png)
	filePath  += pageName;			
	pSpriteFont->m_pTexture = ContentManager::Load<TextureData>(filePath);

	//**********
	// BLOCK 3 *
	//**********
	//Retrieve the blockId and blockSize
	blockId = binReader->Read<char>();
	blockSize = binReader->Read<int>();
	//Retrieve Character Count (see documentation)
	int numChars = blockSize/20;
	pSpriteFont->m_CharacterCount = numChars;
	//Retrieve Every Character, For every Character:
	for (int i = 0; i < numChars; ++i)
	{
		UINT charachterId = binReader->Read<int>();
		if ( pSpriteFont->IsCharValid((wchar_t)charachterId) )
		{
			FontMetric* fontMetric = &pSpriteFont->GetMetric((wchar_t)charachterId);
			fontMetric->IsValid = true;
			fontMetric->Character = (wchar_t)charachterId;
			UINT x = binReader->Read<wchar_t>();
			UINT y = binReader->Read<wchar_t>();
			fontMetric->Width = binReader->Read<wchar_t>();
			fontMetric->Height = binReader->Read<wchar_t>();
			fontMetric->OffsetX = binReader->Read<wchar_t>();
			fontMetric->OffsetY = binReader->Read<wchar_t>();
			fontMetric->AdvanceX = binReader->Read<wchar_t>();
			fontMetric->Page = binReader->Read<char>();
			int channel = binReader->Read<char>();
			if (channel == 1)
			{
				fontMetric->Channel = 2;
			}
			else if (channel == 2)
			{
				fontMetric->Channel = 1;
			}
			else if (channel == 4)
			{
				fontMetric->Channel = 0;
			}
			else if (channel == 8)
			{
				fontMetric->Channel = 3;
			}
			fontMetric->TexCoord.x = (float)x/pSpriteFont->m_TextureWidth;
			fontMetric->TexCoord.y = (float)y/pSpriteFont->m_TextureHeight;
		}
		else
		{
			Logger::LogWarning(L"CharacterId is not valid");
		}
	}

	//> Retrieve CharacterId (store Local) and cast to a 'wchar_t'
	//> Check if CharacterId is valid (SpriteFont::IsCharValid), Log Warning and advance to next character if not valid
	//> Retrieve the corresponding FontMetric (SpriteFont::GetMetric) [REFERENCE!!!]
	//> Set IsValid to true [FontMetric::IsValid]
	//> Set Character (CharacterId) [FontMetric::Character]
	//> Retrieve Xposition (store Local)
	//> Retrieve Yposition (store Local)
	//> Retrieve & Set Width [FontMetric::Width]
	//> Retrieve & Set Height [FontMetric::Height]
	//> Retrieve & Set OffsetX [FontMetric::OffsetX]
	//> Retrieve & Set OffsetY [FontMetric::OffsetY]
	//> Retrieve & Set AdvanceX [FontMetric::AdvanceX]
	//> Retrieve & Set Page [FontMetric::Page]
	//> Retrieve Channel (BITFIELD!!!) 
	//	> See documentation for BitField meaning [FontMetrix::Channel]
	//> Calculate Texture Coordinates using Xposition, Yposition, TextureWidth & TextureHeight [FontMetric::TexCoord]
	//...
	
	//DONE :)

	delete binReader;
	return pSpriteFont;
}

void SpriteFontLoader::Destroy(SpriteFont* objToDestroy)
{
	SafeDelete(objToDestroy);
}
